#include <iostream>
#include <memory>
#include <string>

// 简单工厂
// 把对象的创建封装到一个接口函数中， 通过传入不同的标识，创建对应的对象
// 客户不用自己负责new对象，不用了解对象的创建过程
// 提供创建对象实例的接口函数不闭合，不能对修改关闭
//
// 工厂方法
// Factory基类，提供了一个纯虚函数（创建产品），定义派生类（具体产品的工厂）负责创建对应的产品，可以做到不同的产品，在不同的工厂里面创建，
// 能够对现有工厂以及产品的修改关闭
// 实际上， 很多产品有关联关系，不应当放在不同的工厂类里面去创建，
// 既不符合产品创建逻辑，也容易导致工厂类过多
//
// 抽象工厂
// 把有关联关系的产品的创建放到一个工厂中

class Car {
public:
    Car(const std::string& name) : _name(name) {
    }
    virtual void show() = 0;

protected:
    std::string _name;
};

class Byd : public Car {
public:
    Byd(const std::string& name) : Car(name) {
    }

    void show() {
        std::cout << "Byd"
                  << " " << _name << std::endl;
    }
};
class Audi : public Car {
public:
    Audi(const std::string& name) : Car(name) {
    }

    void show() {
        std::cout << "Audi"
                  << " " << _name << std::endl;
    }
};

#if 0
// 简单工厂
enum class CarType { BYD, AUDI };
class SimpleFactory {
public:
    Car* createCar(CarType carType) {
        switch (carType) {
            case CarType::AUDI:
                return new Audi("A6");
            case CarType::BYD:
                return new Byd("仰望 U8");
            default:
                return nullptr;
        }
    }
};

int main() {
    SimpleFactory* sf = new SimpleFactory;
    std::unique_ptr<Car> car1(sf->createCar(CarType::AUDI));
    std::unique_ptr<Car> car2(sf->createCar(CarType::BYD));

    car1->show();
    car2->show();
}
#endif

#if 0
// 工厂方法
class Factory {
public:
    virtual Car* createCar(const std::string& name) = 0;
};

class BydFactory : public Factory {
public:
    Car* createCar(const std::string& name) {
        return new Byd(name);
    }
};

class AudiFactory : public Factory {
public:
    Car* createCar(const std::string& name) {
        return new Audi(name);
    }
};

int main() {
    std::unique_ptr<Factory> bydFactory(new BydFactory);
    std::unique_ptr<Factory> audiFactory(new AudiFactory);

    std::unique_ptr<Car> byd(bydFactory->createCar("仰望"));
    std::unique_ptr<Car> audi(audiFactory->createCar("A6"));

    byd->show();
    audi->show();
}
#endif

// 抽象工厂
class Light {
public:
    virtual void show() = 0;
};

class BydLight : public Light {
public:
    void show() {
        std::cout << "Byd Light" << std::endl;
    }
};

class AudiLight : public Light {
public:
    void show() {
        std::cout << "Audi Light" << std::endl;
    }
};

class AbstractFactory {
public:
    virtual Car* createCar(const std::string& name) = 0;
    virtual Light* createLight() = 0;
};

class BydFactory : public AbstractFactory {
public:
    Car* createCar(const std::string& name) {
        return new Byd(name);
    }

    Light* createLight() {
        return new BydLight;
    }
};

class AudiFactory : public AbstractFactory {
public:
    Car* createCar(const std::string& name) {
        return new Audi(name);
    }

    Light* createLight() {
        return new AudiLight;
    }
};

int main() {
    std::unique_ptr<AbstractFactory> bydFactory(new BydFactory);
    std::unique_ptr<AbstractFactory> audiFactory(new AudiFactory);

    std::unique_ptr<Car> car1(bydFactory->createCar("仰望"));
    std::unique_ptr<Light> light1(bydFactory->createLight());

    std::unique_ptr<Car> car2(audiFactory->createCar("A6"));
    std::unique_ptr<Light> light2(audiFactory->createLight());

    car1->show();
    light1->show();
    car2->show();
    light2->show();
    return 0;
}
